package com.yc.cloud.admin.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yc.cloud.admin.dto.request.HwDeviceVideoRecordCreateReqDTO;
import com.yc.cloud.admin.dto.request.HwDeviceVideoRecordUpdateReqDTO;
import com.yc.cloud.admin.dto.request.HwDeviceVideoRecordPageReqDto;
import com.yc.cloud.admin.service.HwDeviceVideoRecordService;
import com.yc.cloud.admin.vo.HwDeviceVideoRecordVo;
import com.yc.cloud.common.orm.CommonPage;
import com.yc.cloud.common.oss.entity.OssFile;
import com.yc.cloud.common.oss.service.OssFileService;
import com.yc.cloud.entity.HwCamera;
import com.yc.cloud.entity.HwDevice;
import com.yc.cloud.entity.HwDeviceVideoRecord;
import com.yc.cloud.mapper.AlarmRecordMapper;
import com.yc.cloud.mapper.HwCameraMapper;
import com.yc.cloud.mapper.HwDeviceMapper;
import com.yc.cloud.mapper.HwDeviceVideoRecordMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;

/**
 * <p>
 * 设备录像记录表 服务实现类
 * </p>
 *
 * @author kinggu
 * @since 2025-01-03
 */
@Service
@Slf4j
public class HwDeviceVideoRecordServiceImpl extends ServiceImpl<HwDeviceVideoRecordMapper, HwDeviceVideoRecord>
        implements HwDeviceVideoRecordService {

    @Value("${custom.path.basePath}")
    private String basePath;

    @Resource
    private OssFileService ossFileService;

    @Resource
    private HwDeviceMapper hwDeviceMapper;

    @Resource
    private HwCameraMapper hwCameraMapper;

    @Resource
    private AlarmRecordMapper alarmRecordMapper;

    /**
     * 移动视频文件到项目目录并创建OSSFile记录
     * 
     * @param originalFilePath 原始文件路径
     * @return 文件ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String moveVideoFileAndCreateOssRecord(String originalFilePath) {
        // 构建默认目标路径
        String fileName = FileUtil.getName(originalFilePath);
        String targetPath = buildDefaultTargetPath(fileName);

        // 调用重载方法
        return moveVideoFileAndCreateOssRecord(originalFilePath, targetPath);
    }

    /**
     * 移动视频文件到指定目录并创建OSSFile记录
     * 
     * @param originalFilePath 原始文件路径
     * @param targetPath       目标路径
     * @return 文件ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String moveVideoFileAndCreateOssRecord(String originalFilePath, String targetPath) {
        try {
            // 检查原始文件是否存在
            File originalFile = new File(originalFilePath);
            if (!originalFile.exists()) {
                log.error("Original video file not found: {}", originalFilePath);
                return null;
            }

            // 确保目标目录存在
            String targetDir = FileUtil.getParent(targetPath, 1);
            FileUtil.mkdir(targetDir);

            // 移动文件
            Path sourcePath = Paths.get(originalFilePath);
            Path targetPathObj = Paths.get(targetPath);
            Files.move(sourcePath, targetPathObj, StandardCopyOption.REPLACE_EXISTING);

            log.info("Moved video file from {} to {}", originalFilePath, targetPath);

            // 创建OSSFile记录
            OssFile ossFile = ossFileService.saveOssFile(targetPath);
            if (ossFile != null) {
                log.info("Created OSS file record: fileId={}, path={}", ossFile.getFileId(), targetPath);
                return ossFile.getFileId();
            } else {
                log.error("Failed to create OSS file record for path: {}", targetPath);
                return null;
            }

        } catch (Exception e) {
            log.error("Failed to move video file and create OSS record: originalPath={}, targetPath={}",
                    originalFilePath, targetPath, e);
            return null;
        }
    }

    /**
     * 构建默认目标文件路径
     * 
     * @param fileName 文件名
     * @return 目标路径
     */
    private String buildDefaultTargetPath(String fileName) {
        // 从文件名中提取日期信息，例如：2025-08-14-17-00-17-0.mp4
        String dateStr = extractDateFromFileName(fileName);
        if (StrUtil.isEmpty(dateStr)) {
            dateStr = DateUtil.format(LocalDateTime.now(), "yyyy-MM-dd");
        }

        // 构建路径：basePath/videos/yyyy-MM-dd/fileName
        return Paths.get(basePath, "videos", dateStr, fileName).toString();
    }

    /**
     * 从文件名中提取日期
     * 
     * @param fileName 文件名
     * @return 日期字符串
     */
    private String extractDateFromFileName(String fileName) {
        try {
            // 文件名格式：2025-08-14-17-00-17-0.mp4
            if (fileName.matches("\\d{4}-\\d{2}-\\d{2}-\\d{2}-\\d{2}-\\d{2}-\\d+\\.mp4")) {
                return fileName.substring(0, 10); // 提取 yyyy-MM-dd 部分
            }
        } catch (Exception e) {
            log.warn("Failed to extract date from filename: {}", fileName, e);
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean create(HwDeviceVideoRecordCreateReqDTO createReqDTO) {
        try {
            HwDeviceVideoRecord record = new HwDeviceVideoRecord();
            record.setDeviceId(createReqDTO.getDeviceId());
            record.setCameraId(createReqDTO.getCameraId());
            record.setStream(createReqDTO.getStream());
            record.setStartTime(createReqDTO.getStartTime());
            record.setEndTime(createReqDTO.getEndTime());
            record.setDuration(createReqDTO.getDuration());
            record.setFileSize(createReqDTO.getFileSize());
            record.setOriginalFilePath(createReqDTO.getOriginalFilePath());
            record.setFileId(createReqDTO.getFileId());
            if (StrUtil.isNotEmpty(createReqDTO.getThumbnailFileId())) {
                record.setThumbnailFileId(createReqDTO.getThumbnailFileId());
            }

            return save(record);
        } catch (Exception e) {
            log.error("Failed to create video record", e);
            return false;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean update(HwDeviceVideoRecordUpdateReqDTO updateReqDTO) {
        try {
            HwDeviceVideoRecord record = getById(updateReqDTO.getId());
            if (record == null) {
                log.warn("Video record not found: {}", updateReqDTO.getId());
                return false;
            }

            if (updateReqDTO.getDeviceId() != null) {
                record.setDeviceId(updateReqDTO.getDeviceId());
            }
            if (updateReqDTO.getCameraId() != null) {
                record.setCameraId(updateReqDTO.getCameraId());
            }
            if (StrUtil.isNotEmpty(updateReqDTO.getStream())) {
                record.setStream(updateReqDTO.getStream());
            }
            if (updateReqDTO.getStartTime() != null) {
                record.setStartTime(updateReqDTO.getStartTime());
            }
            if (updateReqDTO.getEndTime() != null) {
                record.setEndTime(updateReqDTO.getEndTime());
            }
            if (updateReqDTO.getDuration() != null) {
                record.setDuration(updateReqDTO.getDuration());
            }
            if (updateReqDTO.getFileSize() != null) {
                record.setFileSize(updateReqDTO.getFileSize());
            }
            if (StrUtil.isNotEmpty(updateReqDTO.getOriginalFilePath())) {
                record.setOriginalFilePath(updateReqDTO.getOriginalFilePath());
            }
            if (StrUtil.isNotEmpty(updateReqDTO.getFileId())) {
                record.setFileId(updateReqDTO.getFileId());
            }
            if (StrUtil.isNotEmpty(updateReqDTO.getThumbnailFileId())) {
                record.setThumbnailFileId(updateReqDTO.getThumbnailFileId());
            }

            return updateById(record);
        } catch (Exception e) {
            log.error("Failed to update video record: {}", updateReqDTO.getId(), e);
            return false;
        }
    }

    @Override
    public HwDeviceVideoRecordVo getVOById(Long id) {
        try {
            HwDeviceVideoRecord record = getById(id);
            if (record == null) {
                return null;
            }

            return convertToVo(record);
        } catch (Exception e) {
            log.error("Failed to get video record by id: {}", id, e);
            return null;
        }
    }

    @Override
    public CommonPage<HwDeviceVideoRecordVo> list(HwDeviceVideoRecordPageReqDto pageReqDTO) {
        try {
            // 构建查询条件
            QueryWrapper<HwDeviceVideoRecord> queryWrapper = new QueryWrapper<>();

            if (pageReqDTO.getDeviceId() != null) {
                queryWrapper.eq(HwDeviceVideoRecord.DeviceId, pageReqDTO.getDeviceId());
            }
            if (pageReqDTO.getCameraId() != null) {
                queryWrapper.eq(HwDeviceVideoRecord.CameraId, pageReqDTO.getCameraId());
            }
            if (StrUtil.isNotEmpty(pageReqDTO.getStream())) {
                queryWrapper.like(HwDeviceVideoRecord.Stream, pageReqDTO.getStream());
            }
            if (pageReqDTO.getStartDate() != null) {
                // 录像的开始时间 >= 查询日期的开始（00:00:00）
                queryWrapper.ge(HwDeviceVideoRecord.StartTime, pageReqDTO.getStartDate().atStartOfDay());
            }
            if (pageReqDTO.getEndDate() != null) {
                // 录像的结束时间 <= 查询日期的结束（23:59:59）
                queryWrapper.le(HwDeviceVideoRecord.EndTime, pageReqDTO.getEndDate().atTime(23, 59, 59));
            }

            // 按创建时间倒序排列
            queryWrapper.orderByDesc("create_time");

            // 分页查询
            Page<HwDeviceVideoRecord> page = new Page<>(pageReqDTO.getPageNum(), pageReqDTO.getPageSize());
            IPage<HwDeviceVideoRecord> pageResult = page(page, queryWrapper);

            // 转换为VO
            CommonPage<HwDeviceVideoRecord> commonPage = CommonPage.restPage(pageResult);
            CommonPage<HwDeviceVideoRecordVo> result = new CommonPage<>();
            result.setPageNum(commonPage.getPageNum());
            result.setPageSize(commonPage.getPageSize());
            result.setTotalPage(commonPage.getTotalPage());
            result.setTotal(commonPage.getTotal());
            result.setList(
                    commonPage.getList().stream().map(this::convertToVo).collect(java.util.stream.Collectors.toList()));

            return result;

        } catch (Exception e) {
            log.error("Failed to list video records", e);

            // 返回空分页结果
            CommonPage<HwDeviceVideoRecordVo> emptyResult = new CommonPage<>();
            emptyResult.setPageNum(pageReqDTO.getPageNum());
            emptyResult.setPageSize(pageReqDTO.getPageSize());
            emptyResult.setTotalPage(0);
            emptyResult.setTotal(0L);
            emptyResult.setList(java.util.Collections.emptyList());
            return emptyResult;
        }
    }

    /**
     * 转换为VO对象
     */
    private HwDeviceVideoRecordVo convertToVo(HwDeviceVideoRecord record) {
        HwDeviceVideoRecordVo vo = new HwDeviceVideoRecordVo();
        BeanUtils.copyProperties(record, vo);

        // 格式化时长
        if (record.getDuration() != null) {
            vo.setDurationFormatted(formatDuration(record.getDuration()));
        }

        // 格式化文件大小
        if (record.getFileSize() != null) {
            vo.setFileSizeFormatted(formatFileSize(record.getFileSize()));
        }

        // 获取设备信息
        if (record.getDeviceId() != null) {
            HwDevice device = hwDeviceMapper.selectById(record.getDeviceId());
            if (device != null) {
                vo.setDeviceName(device.getName());
                vo.setDeviceLocation(device.getLocation());
            }
        }

        // 获取摄像头信息
        if (record.getCameraId() != null) {
            HwCamera camera = hwCameraMapper.selectById(record.getCameraId());
            if (camera != null) {
                vo.setCameraName(camera.getName());
                vo.setCameraLocation(camera.getLocation());
            }
        }

        // 获取文件访问URL
        if (StrUtil.isNotEmpty(record.getFileId())) {
            String fileUrl = ossFileService.getOssFileUrl(record.getFileId());
            vo.setFileUrl(fileUrl);
        }

        // 获取缩略图访问URL
        if (StrUtil.isNotEmpty(record.getThumbnailFileId())) {
            String thumbnailUrl = ossFileService.getOssFileUrl(record.getThumbnailFileId());
            vo.setThumbnailUrl(thumbnailUrl);
        }

        // 统计该录像时间段内的报警数量
        Long alarmCount = alarmRecordMapper.countByDeviceAndTimeRange(
                record.getDeviceId(),
                record.getCameraId(),
                record.getStartTime(),
                record.getEndTime()
        );
        vo.setAlarmCount(alarmCount != null ? alarmCount : 0L);

        return vo;
    }

    /**
     * 格式化时长
     */
    private String formatDuration(Integer seconds) {
        if (seconds == null || seconds <= 0) {
            return "0秒";
        }

        int hours = seconds / 3600;
        int minutes = (seconds % 3600) / 60;
        int secs = seconds % 60;

        if (hours > 0) {
            return String.format("%d时%d分%d秒", hours, minutes, secs);
        } else if (minutes > 0) {
            return String.format("%d分%d秒", minutes, secs);
        } else {
            return String.format("%d秒", secs);
        }
    }

    /**
     * 格式化文件大小
     */
    private String formatFileSize(Long bytes) {
        if (bytes == null || bytes <= 0) {
            return "0B";
        }

        String[] units = { "B", "KB", "MB", "GB", "TB" };
        int unitIndex = 0;
        double size = bytes.doubleValue();

        while (size >= 1024 && unitIndex < units.length - 1) {
            size /= 1024;
            unitIndex++;
        }

        return String.format("%.2f%s", size, units[unitIndex]);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean delete(Long id) {
        // 1. 校验待删除的记录是否存在
        HwDeviceVideoRecord record = getById(id);
        if (record == null) {
            log.warn("录像记录不存在: id={}", id);
            return false;
        }
        
        // 2. 删除关联的OSS文件资源（包括物理文件和数据库记录）
        if (StrUtil.isNotEmpty(record.getFileId())) {
            ossFileService.deleteByFileId(record.getFileId());
        }
        if (StrUtil.isNotEmpty(record.getThumbnailFileId())) {
            ossFileService.deleteByFileId(record.getThumbnailFileId());
        }
        
        // 3. 删除数据库记录
        return removeById(id);
    }
}
